﻿using HalconDotNet;
using ICSharpCode.AvalonEdit.Editing;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Text;
using OpenCvSharp;
using RoslynPad.Editor;
using RoslynPad.Roslyn;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using Document = Microsoft.CodeAnalysis.Document;

namespace PLCSharp.Views.Workflows.Script
{
    public class CustomTextEditor : RoslynCodeEditor
    {
        private static Document _document;

        private RoslynHost _host;

        public CustomTextEditor()
        {
            TextArea.KeyDown += TextBoxEditor_KeyDown;
            TextArea.LostKeyboardFocus += TextArea_LostKeyboardFocus;
            TextArea.GotKeyboardFocus += TextArea_GotKeyboardFocus;
            ICSharpCode.AvalonEdit.Search.SearchPanel.Install(this);
            DataContextChanged += OnDataContextChanged;
            TextArea.Caret.PositionChanged += CaretOnPositionChanged;
        }



        private int caretOffset;
 
        private void CaretOnPositionChanged(object sender, EventArgs e)
        {
            if (coding)
                caretOffset = CaretOffset;
        }
#nullable enable
        private async void OnDataContextChanged(object? sender, DependencyPropertyChangedEventArgs args)
        {
            var workingDirectory = Directory.GetCurrentDirectory();

            _host = new CustomRoslynHost(additionalAssemblies:
            [
                    Assembly.Load("RoslynPad.Roslyn.Windows"),
                    Assembly.Load("RoslynPad.Editor.Windows"),

            ],
            RoslynHostReferences.NamespaceDefault.With(assemblyReferences:
            [
                typeof(object).Assembly,
                typeof(Mat).Assembly,
                typeof(App).Assembly,
                typeof(HObject).Assembly,
            ]
            ));


            var documentId = await InitializeAsync(_host, new ClassificationHighlightColors(),
                workingDirectory, string.Empty, SourceCodeKind.Script);


            _document = _host.GetDocument(documentId);


        }

#nullable disable
        bool coding;
        private void TextArea_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            coding = true;
        }
        private void TextArea_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            coding = false;
 
        }
        private void TextBoxEditor_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.S && Keyboard.Modifiers == ModifierKeys.Control)
            {
                _ = FormatCodeAsync();
            }
        }
        public async Task FormatCodeAsync()
        {
            var textDocument = _document.WithText(SourceText.From(Document.Text));

            var formatDoc = await Formatter.FormatAsync(textDocument);

            var text = await formatDoc.GetTextAsync();

            Document.Text = text.ToString();
            Text = Document.Text;
        }

        public void Insert(string str)
        {
  
            var text = Text;
            text = text.Insert(caretOffset, str);
            Document.Text = text;
            Text = Document.Text;

        }
 
        // <summary>
        /// A bindable Text property
        /// </summary>
        public new string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
            }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
                nameof(Text),
                typeof(string),
                typeof(CustomTextEditor),
                new FrameworkPropertyMetadata
                {
                    DefaultValue = default(string),
                    BindsTwoWayByDefault = true,
                    PropertyChangedCallback = OnDependencyPropertyChanged
                }
            );

        /// <summary>
        /// 属性改变回调
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="args"></param>
        protected static void OnDependencyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var target = (CustomTextEditor)obj;

            if (target.Document != null)
            {
                //var caretOffset = target.CaretOffset;
                var newValue = args.NewValue;
                newValue ??= "";
                var text = (string)newValue;
                target.Document.Text = text;
            }
        }
    }

    public class CustomRoslynHost : RoslynHost
    {
        private bool _addedAnalyzers;

#nullable enable
        public CustomRoslynHost(IEnumerable<Assembly>? additionalAssemblies = null, RoslynHostReferences? references = null, ImmutableHashSet<string>? disabledDiagnostics = null) : base(additionalAssemblies, references, disabledDiagnostics)
        {
        }

#nullable disable

        protected override IEnumerable<AnalyzerReference> GetSolutionAnalyzerReferences()
        {
            if (!_addedAnalyzers)
            {
                _addedAnalyzers = true;
                return base.GetSolutionAnalyzerReferences();
            }

            return [];
        }
    }
}